home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
du.arc
/
DU.C
next >
Wrap
C/C++ Source or Header
|
1990-10-05
|
8KB
|
305 lines
/* @(#) du.c 1.2 90/09/08 14:38:52 */
/*
* Package: du - Enhanced "du" disk usage report generator.
* File: du.c - Main program.
*
* Sat Sep 8 14:34:56 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
* Cleanup for distribution.
* Tue Apr 17 21:50:58 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
* Original composition.
*
* Copyright 1990, Unicom Systems Development. All rights reserved.
* See accompanying README file for terms of distribution and use.
*/
#include <stdio.h>
#define INTERN
#include "du.h"
#include "patchlevel.h"
static char Copyright[] =
"@(#) Copyright 1990, Unicom Systems Development. All rights reserved.";
static char SccsID[] = "@(#) du.c 1.2 90/09/08 14:38:52";
#define USAGE "usage: %s [ options ] [ path ... ] (try '-h' for help)\n"
/*
* Local procedures.
*/
static void do_help();
static void set_breakdown();
/*
* External procedures.
*/
extern char *getcwd();
extern char *strtok();
extern long time();
extern void *malloc();
extern void exit();
main(argc,argv)
int argc;
char *argv[];
{
int i;
extern char *optarg;
extern int optind;
/*
* Initialize.
*/
Progname =argv[0];
Accum_subdirs =TRUE; /* add usage of a subdir into parent's usage */
All_entries =FALSE; /* just show directories */
Cross_filesys =TRUE; /* continue down dirs across filesystems */
Descend_dirs =TRUE; /* follow directories recursively */
Suppress_repeats =TRUE; /* report multiply linked files only once */
#ifdef PRINT_ERRORS
Print_errors =TRUE; /* enable error messages */
#else
Print_errors =FALSE; /* suppress error messages */
#endif
Skip_links =FALSE; /* allow checking of multiply-linked files */
Total_only =FALSE; /* print usage at each directory encountered */
Report_blksize =REPORT_BLKSIZE; /* block size used in reports */
Num_break =1; /* only present on column in the usage report */
Breakdown[0] =0; /* that col should include all existing files */
/*
* Crack command line options.
*/
while ( (i=getopt(argc, argv, "ab:c:dfhilrsu")) != EOF ) {
switch ( i ) {
case 'a': All_entries = TRUE; break;
case 'b': Report_blksize = atoi(optarg); break;
case 'c': set_breakdown(optarg); break;
case 'd': Descend_dirs = FALSE; break;
case 'f': Cross_filesys = FALSE; break;
case 'h': do_help(); exit(0);
case 'i': Accum_subdirs = FALSE; break;
case 'l': Suppress_repeats = FALSE; break;
case 'r': Print_errors = TRUE; break;
case 's': Total_only = TRUE; break;
case 'u': Skip_links = TRUE; break;
default: fprintf(stderr, USAGE, Progname); exit(1);
}
}
/*
* Initialize the filesystem information tables.
*/
fs_initinfo();
/*
* Get the starting directory in case we need to chdir.
*/
if ( (Curr_dir=getcwd((char *)NULL, 256)) == NULL )
errmssg(ERR_ABORT,"couldn't get current working directory");
/*
* Get the time so we can do the breakdown of usage by age.
*/
(void) time(&Curr_time);
/*
* If no arguments specified on the command line then do the current dir.
*/
if ( optind == argc ) {
du_entry(".");
exit(0);
}
/*
* Do all the items given on the command line.
*/
for ( i = optind ; i < argc ; ++i )
du_entry(argv[i]);
exit(0);
/*NOTREACHED*/
}
static char *usage_text[] = {
"",
"du - version %V (patchlevel %L)",
"",
" Usage: %P [ options ] [ path ... ]",
"",
" Options:",
" -a Report all files encountered, not just directories.",
" -b n Report as if disk blocks were 'n' bytes (default %B).",
" (A '0' value reports in native filesystem block size.)",
" -c n,n,... Breakdown by age, one col for each 'n' days or older.",
" -d Do not descend into directories encountered.",
" -f Do cross filesystems.",
" -h Display this help message.",
" -i Do not accumulate subdirectories' usage into parent dir.",
" -l Count multiply linked files each time encountered.",
#ifndef PRINT_ERRORS
" -r Print (don't suppress) errors which occur during scan.",
#endif
" -s Only print a total for each argument on the command line.",
" -u Skip (do not count) multiply linked files entirely.",
"",
"Copyright 1990, Unicom Systems Development. All rights reserved.",
"See distributed README file for terms of distribution and use.",
"",
NULL
};
static void do_help()
{
Reg char *s, **linep;
for ( linep = usage_text ; *linep != NULL ; ++linep ) {
for ( s = *linep ; *s != '\0' ; ++s ) {
if ( *s == '%' ) {
switch ( *++s ) {
case 'B': fprintf(stderr,"%d",REPORT_BLKSIZE); break;
case 'P': fputs(Progname,stderr); break;
case 'V': fputs(VERSION,stderr); break;
case 'L': fprintf(stderr,"%d",PATCHLEVEL); break;
default: putc('%',stderr); putc(*s,stderr); break;
}
} else {
putc(*s,stderr);
}
}
putc('\n', stderr);
}
exit(0);
}
static void set_breakdown(str)
char *str;
{
char *s;
Num_break = 0;
while ( (s=strtok(str, " \t,")) != NULL ) {
if ( Num_break >= MAX_BREAK ) {
fprintf(stderr, "%s: too many breakdown catagories\n", Progname);
exit(1);
}
if ( (Breakdown[Num_break++]=atoi(s)) == 0 && *s != '0' ) {
fprintf(stderr, "%s: bad breakdown value '%s'\n", Progname, s);
exit(1);
}
str = NULL;
}
if ( Num_break == 0 ) {
fprintf(stderr, "%s: no breakdown catagories specified\n", Progname);
exit(1);
}
}
void *xmalloc(n)
unsigned n;
{
char *s;
if ( (s=malloc(n)) == NULL ) {
fputs("malloc: out of space\n",stderr);
exit(1);
}
return s;
}
/*
* Error Message Interface - The errmssg() routine uses a printf-like syntax
* to display an error message. If "errno" is nonzero, it will be included
* in the diagnostic message.
*/
#include <varargs.h>
/*VARARGS1*/
void errmssg(severity, fmt, va_alist)
int severity;
char *fmt;
va_dcl
{
va_list args;
int save_errno;
extern int errno;
extern char *sys_errlist[];
if ( !Print_errors && severity < ERR_ABORT )
return;
save_errno = errno;
va_start(args);
fprintf(stderr, "%s: ", Progname);
vfprintf(stderr, fmt, args);
if ( save_errno > 0 )
fprintf(stderr, " (%s)", sys_errlist[save_errno]);
putc('\n',stderr);
va_end(args);
if ( severity >= ERR_ABORT )
exit(1);
}
/*
* Disk Usage Functions - Disk usage is stored in a (struct dskusage) datatype.
* The following routines provide all the required manipulations of this
* datatype, and no knowledge of the internals of this structure exists
* outside these routines. The following functions are provided:
*
* set_usage() - Load a (struct dskusage) from file information.
* add_usage() - Accumulate data from one (struct dskusage) into another.
* print_usage() - Print statistics from a (struct dskusage).
*/
#include <sys/types.h>
#include <sys/stat.h>
void set_usage(usage, sbufp, nblocks)
Reg struct dskusage *usage;
struct stat *sbufp;
Reg long nblocks;
{
Reg int i;
long ndays;
/*
* The following luckily works out OK. If a file is created after "du"
* is started, the "Curr_time-sbufp->st_mtime" value will be a small
* negative number, however when divided by "60*60*24" it will truncate
* to zero, so it will be counted in the breakdown OK.
*/
ndays = (Curr_time - sbufp->st_mtime) / ( 60*60*24 /* sec per day */ );
for ( i = Num_break-1 ; i >= 0 ; --i )
usage->b[i] = ( Breakdown[i] <= ndays ? nblocks : 0L );
}
void add_usage(tot_usage, ent_usage)
Reg struct dskusage *tot_usage, *ent_usage;
{
Reg int i;
for ( i = 0 ; i < Num_break ; ++i )
tot_usage->b[i] += ent_usage->b[i];
}
void print_usage(name, usage)
char *name;
struct dskusage *usage;
{
int i;
for ( i = 0 ; i < Num_break ; ++i )
printf("%ld\t", usage->b[i]);
printf("%s\n", name);
}